/*
 * *******************************************************************
 *   @项目名称: BHex Android
 *   @文件名称: FuturesCalculationFormula.java
 *   @Date: 19-8-6 下午7:22
 *   @Author: ppzhao
 *   @Description:
 *   @Copyright（C）: 2019 BlueHelix Inc.   All rights reserved.
 *   注意：本内容仅限于内部传阅，禁止外泄以及用于其他的商业目的.
 *  *******************************************************************
 */

package io.bhex.app.utils;

import io.bhex.app.R;
import io.bhex.app.app.BHexApplication;
import io.bhex.baselib.utils.DebugLog;
import io.bhex.baselib.utils.NumberUtils;
import io.bhex.baselib.utils.ToastUtils;
import io.bhex.sdk.data_manager.SymbolDataManager;
import io.bhex.sdk.quote.bean.CoinPairBean;
import io.bhex.sdk.quote.bean.FuturensBaseToken;
import io.bhex.sdk.quote.bean.RiskLimitBean;
import io.bhex.sdk.trade.futures.bean.FuturesPositionOrder;

/**
 * 期货计算公式
 */
public class FuturesCalculationFormula {


    /**
     * 预估强平价
     * <p>
     * [正向合约]
     * 多仓：(开仓价值 - 持仓保证金 - 输入的保证金) / ((1 - 维持保证金率) * 合约乘数 * 手数)
     * 空仓：(开仓价值 + 持仓保证金 + 输入的保证金) / ((1 + 维持保证金率) * 合约乘数 * 手数)
     * <p>
     * [反向合约]
     * <p>
     * 多仓： ((1 + 维持保证金率) * 合约乘数 * 手数) / (累计开仓价值 + 累计起始保证金 + 累计追加保证金)
     * 多仓： ((1 + 维持保证金率) * 合约乘数 * 手数) / (累计开仓价值 +持仓保证金 + 用户追加保证金)
     * <p>
     * 空仓： ((1 - 维持保证金率) * 合约乘数 * 手数) / (累计开仓价值 - 累计起始保证金 - 累计追加保证金)
     * 空仓： ((1 - 维持保证金率) * 合约乘数 * 手数) / (累计开仓价值 - 持仓保证金 - 用户追加保证金)
     *
     * <p>
     * 开仓价值 = item.positionValues
     * 持仓保证金 = item.margin
     * 维持保证金率 = item.marginRate
     * 手数 = item.total
     * 合约乘数 = symbol_info.baseTokenFutures.contractMultiplier
     */
    public static String calForceClosePrice(String inputMargin, FuturesPositionOrder mHoldOrderBean, RiskLimitBean currentRiskLimitBean) {
        if (mHoldOrderBean == null) {
            DebugLog.e("NULL", "calForceClosePrice: mHoldOrderBean symbol info is null");
            return "";
        }
        String symbolId = mHoldOrderBean.getSymbolId();
        //开仓价值  正向：均价*持仓量   反向：（1 / 均价） * 持仓量
        String positionValues = "";

        //持仓保证金
        String margin = mHoldOrderBean.getMargin();
        //维持保证金率
        String marginRate = currentRiskLimitBean.getMaintainMargin();
        //持仓手数
        String total = mHoldOrderBean.getTotal();

        CoinPairBean coinPairBean = SymbolDataManager.GetInstance().getFuturesSymbolInfoById(symbolId);
        if (coinPairBean == null) {
            DebugLog.e("NULL", "calForceClosePrice: futures symbol info is null");
            ToastUtils.showShort(BHexApplication.getInstance().getString(R.string.string_data_exception));
            return "";
        }
        boolean isReverse = coinPairBean.isReverse();
        String priceUnit = KlineUtils.getFuturesPriceUnit(coinPairBean.getSymbolId());
        int quoteTokenDigit = SymbolDataManager.GetInstance().getTokenDigitBySymbolIdAndTokenId(coinPairBean.getSymbolId() + coinPairBean.getQuoteTokenId());
        FuturensBaseToken baseTokenFutures = coinPairBean.baseTokenFutures;
        double dValue = 0d;
        if (baseTokenFutures != null) {
            //合约乘数
            String contractMultiplier = baseTokenFutures.getContractMultiplier();

            if (isReverse) {
                positionValues = NumberUtils.mul(NumberUtils.mul(NumberUtils.div(mHoldOrderBean.getAvgPrice(), "1.0")+"",contractMultiplier) + "", total) + "";
            } else {
                positionValues = NumberUtils.mul(NumberUtils.mul(mHoldOrderBean.getAvgPrice(),contractMultiplier)+"", total) + "";
            }

            String isLong = mHoldOrderBean.getIsLong();//仓位方向: 1=多仓，0=空仓
            if (isLong.equals("1")) {
                //1=多仓
                if (isReverse) { //反向合约
                    // ((1 + 维持保证金率) * 合约乘数 * 手数) / (累计开仓价值 +持仓保证金 + 用户追加保证金)
                    String dividend = NumberUtils.mul(NumberUtils.mul(NumberUtils.add("1", marginRate) + "", contractMultiplier) + "", total) + "";
                    String divisor = NumberUtils.add(NumberUtils.add(positionValues, margin) + "", inputMargin) + "";
                    dValue = NumberUtils.div(divisor, dividend);

                } else { //正向合约
                    //被除数
                    String dividend = NumberUtils.sub(NumberUtils.sub(positionValues, margin) + "", inputMargin) + "";
                    //除数
                    String divisor = NumberUtils.mul(NumberUtils.mul(NumberUtils.sub("1", marginRate) + "", contractMultiplier) + "", total) + "";
                    dValue = NumberUtils.div(divisor, dividend);
                }

            } else if (isLong.equals("0")) {
                //0=空仓
                if (isReverse) { //反向合约
                    // 空仓： ((1 - 维持保证金率) * 合约乘数 * 手数) / (累计开仓价值 - 持仓保证金 - 用户追加保证金)
                    String dividend = NumberUtils.mul(NumberUtils.mul(NumberUtils.sub("1", marginRate) + "", contractMultiplier) + "", total) + "";
                    String divisor = NumberUtils.sub(NumberUtils.sub(positionValues, margin) + "", inputMargin) + "";
                    dValue = NumberUtils.div(divisor, dividend);
                } else {//正向合约
                    //被除数
                    String dividend = NumberUtils.add(NumberUtils.add(positionValues, margin) + "", inputMargin) + "";
                    //除数
                    String divisor = NumberUtils.mul(NumberUtils.mul(NumberUtils.add("1", marginRate) + "", contractMultiplier) + "", total) + "";

                    dValue = NumberUtils.div(divisor, dividend);
                }
            }

            if (dValue >= 0d) {
                String forceClosePrice = NumberUtils.roundFormatDown(dValue, quoteTokenDigit) + " " + priceUnit;
                return forceClosePrice;
            }
        }

        return "0 " + priceUnit;
    }

    /**
     * 计算可开张数
     *
     * @param coinPairBean
     * @param isReverseContract
     * @param price
     * @param contractMultiplier
     * @param useLever
     * @param available
     * @return
     */
    public static String calOpenQuantity(CoinPairBean coinPairBean, boolean isReverseContract, String price, String contractMultiplier, String useLever, String available) {
        if (coinPairBean == null) {
            DebugLog.e("NULL", "calForceClosePrice: futures symbol info is null");
            return "";
        }
        int baseTokenDigit = SymbolDataManager.GetInstance().getTokenDigitBySymbolIdAndTokenId(coinPairBean.getSymbolId() + coinPairBean.getBaseTokenId());

        FuturensBaseToken baseTokenFutures = coinPairBean.baseTokenFutures;
        if (baseTokenFutures != null) {
            if (isReverseContract) {
                price = NumberUtils.div(price, "1") + "";
            }

            String enlargeAssets = NumberUtils.mul(available, useLever) + "";
            String realPrice = NumberUtils.mul(price, contractMultiplier) + "";

            return NumberUtils.roundFormatDown(NumberUtils.div(realPrice, enlargeAssets) + "", baseTokenDigit);
        } else {
            return "";
        }

    }

    /**
     * 计算实际交易成本
     *
     * @param coinPairBean
     * @param isReverseContract
     * @param price
     * @param contractMultiplier
     * @param useLever
     * @param quantity
     * @return
     */
    public static String calCostPrice(CoinPairBean coinPairBean, boolean isReverseContract, String price, String contractMultiplier, String useLever, String quantity) {
        if (coinPairBean == null) {
            DebugLog.e("NULL", "calForceClosePrice: futures symbol info is null");
            return "";
        }
        int quoteTokenDigit = SymbolDataManager.GetInstance().getTokenDigitBySymbolIdAndTokenId(coinPairBean.getSymbolId() + coinPairBean.getQuoteTokenId());

        FuturensBaseToken baseTokenFutures = coinPairBean.baseTokenFutures;
        if (baseTokenFutures != null) {
            if (isReverseContract) {
                price = NumberUtils.div(price, "1") + "";
            }

            String realPrice = NumberUtils.mul(price, contractMultiplier) + "";
            String costPrice = NumberUtils.mul(realPrice, quantity) + "";

            return NumberUtils.roundFormatDown(NumberUtils.div(useLever, costPrice) + "", quoteTokenDigit);
        } else {
            return "";
        }

    }
}
